/*
 * Main.java
 *
 * --- Last Update: 8/7/2013 ---
 *
 * Update Notes 8/7/2013 by Bryan Pauquette:
 * Changed tns references to database references
 *
 * Update Notes 8/9/2010 7:05 PM by Adrian Wijasa:
 * Now force the user to login when Main Menu > Import a CSV File into Database is clicked.
 * Fixed the wording "Insert a CSV File into Database" to "Import a CSV File into Database" at Main Menu.
 *
 * Update Notes 6/20/2010 3:57 PM by Adrian Wijasa:
 * This class is now compatible with PostgreSQL.
 *
 * Update Notes 6/19/2010 6:52 PM by Adrian Wijasa:
 * Simplified checkConnection method. It is now only used when an Excel file is being loaded into CSV Data
 * Snapshot.
 *
 * Update Notes 6/18/2010 9:09 PM by Adrian Wijasa:
 * Login is now required to load CSV Data Snapshot.  This is needed to determine the DB Data Types that are
 * going to be used.
 *
 * Update Notes 6/17/2010 11:12 PM by Adrian Wijasa:
 * In getValidatedValue(), to convert field value from String to Date, now this class uses str_to_date to
 * convert it to a MySQL date.
 *
 * Also, in MySQL, & is not used for user input.  Manipulation on field value that contains & is not needed
 * when MySQL is used.
 *
 * Update Notes 6/16/2010 10:37 PM by Adrian Wijasa:
 * Changed the wording of texts and variables to avoid any specific mention of Oracle.
 * Changed the wording "CSV Insert" to "CSV Import".
 *
 * Update Notes 5/20/2010 1:51 PM by Adrian Wijasa:
 * Enable Main if any exception is caught in popUpPlanWindow().
 *
 * Update Notes 5/18/2010 2:12 AM by Adrian Wijasa:
 * Deprecated getValidatedSchema that turns the inputted schema into upper case.  CSV Loader now works with
 * case sensitive databases such as MySQL and PostgreSQL.  Always turning schemas into upper cause will cause
 * conflicts with the case sensitive databases.
 * 
 * Now displays error messages related to ColumnNotConfiguredException.
 *
 * Update Notes 5/13/2010 6:26 PM by Adrian Wijasa:
 * Now processes DB Type information.
 *
 * Update Notes 4/23/2010 8:55 PM by Adrian Wijasa:
 * Added a planFrame Object, so that it's accessible from PlanPanel.
 * Added a new method: getValidatedValue( String value, String dataType ).
 *
 * Update Notes 4/18/2010 11:57 AM by Adrian Wijasa:
 * This class is made to work with Java 5.
 *
 * Update Notes 4/15/2010 11:31 PM by Adrian Wijasa:
 * Added a new method: popUpPlanWindow().
 * Main class is now popping up a window containing Insert/Merge Plan instead of saving it into a file right
 * away.
 *
 * Update Notes 4/6/2010 10:10 PM by Adrian Wijasa:
 * Added a function that validates the Schema Text Field Inputs: getValidatedSchema( String schema).
 *
 * Update Notes 3/22/2010 9:07 PM by Adrian Wijasa:
 * Added a new menu: Help > About.
 * Changed the UI to Metal.
 *
 * Update Notes 1/31/2010 12:10 AM by Adrian Wijasa:
 * Renamed SAVE_SQL to SAVE_SQL_INSERT.
 * In checkConnection method, invoke FileChooserFrame task: SAVE_SQL_MERGE when toDoAfterLogin is
 * CREATE_SQL_MERGE.
 *
 * Created on February 28, 2007, 1:46 PM
 *
 * CSV Loader
 * Copyright 2007, 2009, 2010 Adrian Wijasa
 *
 * This file is part of CSV Loader.
 *
 * CSV Loader is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * CSV Loader is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with CSV Loader.  If not, see <http://www.gnu.org/licenses/>.
 */

package forms;

import csv.ColumnNotConfiguredException;
import panels.CSVPanel;
import panels.DatabasePanel;
import panels.WelcomePanel;
import java.awt.Color;
import java.sql.SQLException;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Vector;
import sql.CSBIDGen;
import sql.ExistingPIDMQuery;
import sql.PIDMGen;
import sql.SJUIDGen;

/**
 * Main Window of CSV Loader
 * 
 * @author matianyuan
 */
public class Main extends javax.swing.JFrame {

    /** Creates new form Main */
    public Main() {

        /* These two colors will be used by program clickables */
        black = new Color( 0, 0, 0 );
        blue = new Color( 0, 102, 255 );
        red = new Color( 255, 0 , 0 );

        initComponents();
        addWelcomeTab();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        tabbedPane = new javax.swing.JTabbedPane();
        menuBar = new javax.swing.JMenuBar();
        mainMenu = new javax.swing.JMenu();
        csvMenuItem = new javax.swing.JMenuItem();
        connMenuItem = new javax.swing.JMenuItem();
        tnsMenuItem = new javax.swing.JMenuItem();
        menuSeparator = new javax.swing.JSeparator();
        quitMenuItem = new javax.swing.JMenuItem();
        tnsMenu = new javax.swing.JMenu();
        uploadMenuItem = new javax.swing.JMenuItem();
        appendMenuItem = new javax.swing.JMenuItem();
        csvMenu = new javax.swing.JMenu();
        csvUploadMenuItem = new javax.swing.JMenuItem();
        cfgUploadMenuItem = new javax.swing.JMenuItem();
        helpMenu = new javax.swing.JMenu();
        aboutMenuItem = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("CSV Loader 2.2");

        mainMenu.setText("Main Menu");

        csvMenuItem.setText("Import a CSV File into Database");
        csvMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                csvMenuItemActionPerformed(evt);
            }
        });
        mainMenu.add(csvMenuItem);

        connMenuItem.setText("Set the Database Connection Parameters");
        connMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                connMenuItemActionPerformed(evt);
            }
        });
        mainMenu.add(connMenuItem);

        tnsMenuItem.setText("Maintain Database Names");
        tnsMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                tnsMenuItemActionPerformed(evt);
            }
        });
        mainMenu.add(tnsMenuItem);
        mainMenu.add(menuSeparator);

        quitMenuItem.setText("Quit");
        quitMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                quitMenuItemActionPerformed(evt);
            }
        });
        mainMenu.add(quitMenuItem);

        menuBar.add(mainMenu);

        tnsMenu.setText("Database Maintenance");
        tnsMenu.setEnabled(false);

        uploadMenuItem.setText("Upload Databases.xml");
        uploadMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                uploadMenuItemActionPerformed(evt);
            }
        });
        tnsMenu.add(uploadMenuItem);

        appendMenuItem.setText("Append Databases.xml");
        appendMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                appendMenuItemActionPerformed(evt);
            }
        });
        tnsMenu.add(appendMenuItem);

        menuBar.add(tnsMenu);

        csvMenu.setText("CSV Import");
        csvMenu.setEnabled(false);

        csvUploadMenuItem.setText("Upload CSV");
        csvUploadMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                csvUploadMenuItemActionPerformed(evt);
            }
        });
        csvMenu.add(csvUploadMenuItem);

        cfgUploadMenuItem.setText("Upload Configuration");
        cfgUploadMenuItem.setEnabled(false);
        cfgUploadMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cfgUploadMenuItemActionPerformed(evt);
            }
        });
        csvMenu.add(cfgUploadMenuItem);

        menuBar.add(csvMenu);

        helpMenu.setText("Help");

        aboutMenuItem.setText("About");
        aboutMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                aboutMenuItemActionPerformed(evt);
            }
        });
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        setJMenuBar(menuBar);

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(tabbedPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 780, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(tabbedPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 557, Short.MAX_VALUE)
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void csvMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_csvMenuItemActionPerformed
        addCSVTab();
        checkConnection( DBLoginFrame.UPLOAD_CSV_DATA_SNAPSHOT );
}//GEN-LAST:event_csvMenuItemActionPerformed

    private void connMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_connMenuItemActionPerformed
        popUpDBLogin( DBLoginFrame.DO_NOTHING );
}//GEN-LAST:event_connMenuItemActionPerformed

    private void tnsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tnsMenuItemActionPerformed
        addDatabaseTab();
}//GEN-LAST:event_tnsMenuItemActionPerformed

    private void quitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_quitMenuItemActionPerformed
        System.exit( 0 );
}//GEN-LAST:event_quitMenuItemActionPerformed

    private void uploadMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_uploadMenuItemActionPerformed
        popUpFileChooser( FileChooserFrame.UPLOAD_DATABASE_CONFIGURATION );
}//GEN-LAST:event_uploadMenuItemActionPerformed

    private void appendMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_appendMenuItemActionPerformed
        popUpFileChooser( FileChooserFrame.APPEND_DATABASE_CONFIGURATION );
}//GEN-LAST:event_appendMenuItemActionPerformed

    private void csvUploadMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_csvUploadMenuItemActionPerformed
        checkConnection( DBLoginFrame.UPLOAD_CSV_DATA_SNAPSHOT );
}//GEN-LAST:event_csvUploadMenuItemActionPerformed

    private void cfgUploadMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cfgUploadMenuItemActionPerformed
        popUpFileChooser( FileChooserFrame.UPLOAD_IMAGE );
}//GEN-LAST:event_cfgUploadMenuItemActionPerformed

    private void aboutMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_aboutMenuItemActionPerformed
        setEnabled( false );
        LicenseFrame licenseFrame = new LicenseFrame( this );
        licenseFrame.setVisible( true );
}//GEN-LAST:event_aboutMenuItemActionPerformed

    /* Add a tab that is used to configure the CSV file to be Uploaded */
    public void addCSVTab() {
        csvPanel = new CSVPanel( this );
        tabbedPane.addTab( "CSV Import", csvPanel );
        tabbedPane.setSelectedComponent( csvPanel );
        csvMenu.setEnabled( true ); // Enable the menu related to CSV Loader
        cfgUploadMenuItem.setEnabled( false );

        /*
            Disable the menu and clickable that open CSV Loader Tab, closing the
            possibility of opening more than one CSV Loader Tabs
         */
        csvMenuItem.setEnabled( false );
        welcomePanel.csvLabel.setEnabled( false );
    }

    /* Add a column to the CSV Data Snapshot, containing the PIDMs derived from other information */
    public void addExistingPIDMCol( int sourceColIndex, int sourceType ) {
        setTitle( "CSV Loader 2.2 - Loading..." );

        try {
            ExistingPIDMQuery pidmQuery = new ExistingPIDMQuery( this, sourceColIndex, sourceType );
            csvPanel.currentImage.add( pidmQuery.getPidms() );
            csvPanel.reloadCSVTable();
        }
        catch( ClassNotFoundException ce ) {
            JOptionPane.showMessageDialog( null, ce.getMessage(), "JDBC Error", JOptionPane.ERROR_MESSAGE );
        }
        catch( SQLException se ) {
            JOptionPane.showMessageDialog( null, se.getMessage(), "SQL Error", JOptionPane.ERROR_MESSAGE );
        }

        setTitle( "CSV Loader 2.2" );
        setEnabled( true );
        requestFocus();
    }

    /* Add a new column containing new CSB IDs to the CSV Data Snapshot */
    public void addNewCSBIDCol() {
        setEnabled( false );

        setTitle( "CSV Loader 2.2 - Loading..." );

        try {
            CSBIDGen idGen = new CSBIDGen( this );
            csvPanel.currentImage.add( idGen.getIDs() );
            csvPanel.reloadCSVTable();
        }
        catch( SQLException e ) {
            JOptionPane.showMessageDialog( null, e.getMessage(), "SQL Error", JOptionPane.ERROR_MESSAGE );
        }

        setTitle( "CSV Loader 2.2" );
        setEnabled( true );
        requestFocus();
    }

    /* Add a new column containing new PIDMs to the CSV Data Snapshot */
    public void addNewPIDMCol() {
        setEnabled( false );

        setTitle( "CSV Loader 2.2 - Loading..." );

        try {
            PIDMGen pidmGen = new PIDMGen( this );
            csvPanel.currentImage.add( pidmGen.getPidms() );
            csvPanel.reloadCSVTable();
        }
        catch( SQLException e ) {
            JOptionPane.showMessageDialog( null, e.getMessage(), "SQL Error", JOptionPane.ERROR_MESSAGE );
        }

        setTitle( "CSV Loader 2.2" );
        setEnabled( true );
        requestFocus();
    }

    /* Add a new column containing new SJU IDs to the CSV Data Snapshot */
    public void addNewSJUIDCol() {
        setEnabled( false );
        
        setTitle( "CSV Loader 2.2 - Loading..." );

        try {
            SJUIDGen idGen = new SJUIDGen( this );
            csvPanel.currentImage.add( idGen.getIDs() );
            csvPanel.reloadCSVTable();
        }
        catch( SQLException e ) {
            JOptionPane.showMessageDialog( null, e.getMessage(), "SQL Error", JOptionPane.ERROR_MESSAGE );
        }

        setTitle( "CSV Loader 2.2" );
        setEnabled( true );
        requestFocus();
    }

    /* Add a tab that is used to maintain the TNS configurations */
    public void addDatabaseTab() {
        databasePanel = new DatabasePanel( this );
        tabbedPane.addTab( "Database Maintenance", databasePanel );
        tabbedPane.setSelectedComponent( databasePanel );
        tnsMenu.setEnabled( true ); // Enable the menu related to TNS Names Maintenance

        /*
            Disable the menu and clickable that open TNS Maintenance Tab,
            closing the possibility of opening more than one TNS Tabs
         */
        tnsMenuItem.setEnabled( false );
        welcomePanel.databaseLabel.setEnabled( false );
    }

    /* Add a Welcome Tab */
    private void addWelcomeTab() {
        welcomePanel = new WelcomePanel( this );
        tabbedPane.addTab( "Welcome", welcomePanel );
    }

    /* Login to Database before performing a task */
    public void checkConnection( int toDoAfterLogin ) {
        if( user != null ) {
            popUpFileChooser( FileChooserFrame.UPLOAD_CSV );
        }
        else {
            popUpDBLogin( toDoAfterLogin );
        }
    }

    public LinkedList<LinkedList<String>> get2DLinkedList( ArrayList<ArrayList<String>> inArrayList ) {
        LinkedList<LinkedList<String>> outLinkedList = new LinkedList<LinkedList<String>>();

        for( ArrayList<String> rowArrayList: inArrayList ) {
            outLinkedList.add( new LinkedList<String>( rowArrayList ) );
        }

        return outLinkedList;
    }

    public Vector<Vector<String>> get2DVector( ArrayList<ArrayList<String>> inArrayList ) {
        Vector<Vector<String>> outVector = new Vector<Vector<String>>();

        for( ArrayList<String> rowArrayList: inArrayList ) {
            outVector.add( new Vector<String>( rowArrayList ) );
        }

        return outVector;
    }

    public Vector<Vector<String>> get2DVector( LinkedList<LinkedList<String>> inLinkedList ) {
        Vector<Vector<String>> outVector = new Vector<Vector<String>>();

        for( LinkedList<String> rowLinkedList: inLinkedList ) {
            outVector.add( new Vector<String>( rowLinkedList ) );
        }

        return outVector;
    }

    /* Returns a value that is parsed so that it works in SQL DML statements */
    public String getValidatedValue( String value, String dataType ) {
        value = value.trim();

        /*
         *  Do not enclose the value with single quotes (') if it is:
         *  1. sysdate
         *  2. user
         *  3. soundex()
         *  4. wijasa.yukshrd.f_search_name()
         *  5. yukshrd.f_search_name()
         */
        if( value.toLowerCase().equals( "sysdate" ) ||
            value.toLowerCase().equals( "user" ) ||
            value.toLowerCase().matches( "soundex(.*)" ) ||
            value.toLowerCase().matches( "wijasa.yukshrd.f_search_name(.*)" ) ||
            value.toLowerCase().matches( "yukshrd.f_search_name(.*)" ) )
            return value;
        else if( value.equals( "" ) )
            return "null";
        else if( dataType.substring( 0, 4 ).equals( "DATE" ) )
            if( dbType.equals( "MySQL" ) )
                return "str_to_date( '" + value + "', '" + dataType.substring( 6, dataType.lastIndexOf( ")" ) ) + "' )";
            else
                return "to_date( '" + value + "', '" + dataType.substring( 6, dataType.lastIndexOf( ")" ) ) + "' )";
        else {
            value = value.replaceAll( "'", "''" );

            if( dbType.equals( "Oracle" ) )
                value = value.replaceAll( "&", "' || '&' || '" );

            return "'" + value + "'";
        }
    }

    /* Pop Up a Database Column Selector */
    public void popUpDBColSelector() {
        try {
            new ColConfigFrame( this ).setVisible( true );

            setEnabled( false );
        }
        catch( ClassNotFoundException ce ) {
            JOptionPane.showMessageDialog( null, ce.getMessage(), "JDBC Driver Error", JOptionPane.ERROR_MESSAGE );
        }
        catch( SQLException se ) {
            JOptionPane.showMessageDialog( null, se.getMessage(), "SQL Error", JOptionPane.ERROR_MESSAGE );
        }
    }
    
    /* Pop Up a Database Login Window */
    public void popUpDBLogin( int toDoAfterLogin ) {
        new DBLoginFrame( this, toDoAfterLogin );
        setEnabled( false );
    }

    /* Pop up a File Chooser before performing a task that is related to opening/saving a file */
    public void popUpFileChooser( int task ) {
        if( task == FileChooserFrame.SAVE_DATA_COMPARISON )
            planFrame.setEnabled( false );
        else
            setEnabled( false );
        
        fileChooser = new FileChooserFrame( this, task );
        fileChooser.setVisible( true );
    }

    /* Pop Up a Plan window */
    public void popUpPlanWindow() {
        try {
            planFrame = new PlanFrame( this );

            planFrame.setVisible( true );

            setEnabled( false );
        }
        catch( ClassNotFoundException ce ) {
            JOptionPane.showMessageDialog( null, ce.getMessage(), "JDBC Driver Error", JOptionPane.ERROR_MESSAGE );
            setEnabled( true );
            requestFocus();
        }
        catch( ColumnNotConfiguredException colE ) {
            JOptionPane.showMessageDialog( null, colE.getMessage(), "Column Config Error", JOptionPane.ERROR_MESSAGE );
            setEnabled( true );
            requestFocus();
        }
        catch( SQLException se ) {
            JOptionPane.showMessageDialog( null, se.getMessage(), "SQL Error", JOptionPane.ERROR_MESSAGE );
            setEnabled( true );
            requestFocus();
        }
    }

    /* Save the connection parameters into variables in Main */
    void setConnectionParams( String user, String password, String host, int port, String sid, String dbType ) {
        this.user = user;
        this.password = password;
        this.host = host;
        this.port = port;
        this.sid = sid;
        this.dbType = dbType;

        welcomePanel.userValueLabel.setText( user );
        welcomePanel.hostValueLabel.setText( host );
        welcomePanel.portValueLabel.setText( "" + port );
        welcomePanel.sidValueLabel.setText( sid );
        welcomePanel.dbValueLabel.setText( dbType );
    }

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        try {
            UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );

            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    new Main().setVisible(true);
                }
            });
        }
        catch( Exception e ) {
            JOptionPane.showMessageDialog( null, e.getMessage(), "User Interface Error", JOptionPane.ERROR_MESSAGE );
        }
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenuItem aboutMenuItem;
    private javax.swing.JMenuItem appendMenuItem;
    public javax.swing.JMenuItem cfgUploadMenuItem;
    private javax.swing.JMenuItem connMenuItem;
    public javax.swing.JMenu csvMenu;
    public javax.swing.JMenuItem csvMenuItem;
    private javax.swing.JMenuItem csvUploadMenuItem;
    private javax.swing.JMenu helpMenu;
    private javax.swing.JMenu mainMenu;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JSeparator menuSeparator;
    private javax.swing.JMenuItem quitMenuItem;
    public javax.swing.JTabbedPane tabbedPane;
    public javax.swing.JMenu tnsMenu;
    public javax.swing.JMenuItem tnsMenuItem;
    private javax.swing.JMenuItem uploadMenuItem;
    // End of variables declaration//GEN-END:variables

    public Color black; // Clickable Hover Color
    public Color blue;  // Clickable Normal Color
    public Color red;   // Invalid Text Color
    public CSVPanel csvPanel;
    public FileChooserFrame fileChooser;
    public int port;
    public PlanFrame planFrame;
    public String dbType;
    public String host;
    public String password;
    public String sid;
    public String user;
    public DatabasePanel databasePanel;
    public WelcomePanel welcomePanel;
}
